package com.example.archivemanagement.service.impl;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.archivemanagement.entity.Archive;
import com.example.archivemanagement.mapper.ArchiveMapper;
import com.example.archivemanagement.service.ArchiveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class ArchiveServiceImpl extends ServiceImpl<ArchiveMapper, Archive> implements ArchiveService {

    @Value("${file.upload-dir}")
    private String uploadDir;

    @Override
    @Transactional
    public Archive uploadArchive(MultipartFile file, Archive archive) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        String originalFileName = StringUtils.cleanPath(file.getOriginalFilename());

        // 验证文件名合法性
        if (originalFileName.contains("..")) {
            throw new IllegalArgumentException("文件名包含非法字符");
        }

        String fileExtension = getFileExtension(originalFileName);
        String newFileName = UUID.randomUUID() + fileExtension;

        Path uploadPath = Paths.get(uploadDir).toAbsolutePath().normalize();

        try {
            // 确保上传目录存在
            Files.createDirectories(uploadPath);

            // 使用try-with-resources确保输入流自动关闭
            try (InputStream inputStream = file.getInputStream()) {
                Path filePath = uploadPath.resolve(newFileName);

                // 使用REPLACE_EXISTING选项防止文件冲突
                Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);

                // 设置文件元数据
                archive.setFilePath(filePath.toString());
                archive.setFileType(fileExtension.substring(1).toUpperCase());
                archive.setFileSize(formatFileSize(file.getSize()));

                save(archive);
                return archive;
            }
        } catch (IOException e) {
            // 上传失败时尝试删除残留文件
            try {
                Path failedFilePath = uploadPath.resolve(newFileName);
                Files.deleteIfExists(failedFilePath);
            } catch (IOException ex) {
                // 记录日志但不影响主异常
               ex.printStackTrace();
            }

            throw new RuntimeException("上传文件失败: " + originalFileName, e);
        }
    }

    private String getFileExtension(String fileName) {
        if (fileName == null || fileName.lastIndexOf('.') == -1) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf('.'));
    }

    @Override
    public Page<Archive> getRecentArchives(boolean isAdmin, int page, int size) {
        Page<Archive> pageable = new Page<>(page, size);
        if (isAdmin) {
            return page(pageable, new QueryWrapper<Archive>().orderByDesc("create_time"));
        } else {
            return page(pageable, new QueryWrapper<Archive>().eq("security_level", "公开").orderByDesc("create_time"));
        }
    }

    @Override
    public Page<Archive> searchArchives(boolean isAdmin, String keyword, String category, String securityLevel, int page, int size) {
        QueryWrapper<Archive> queryWrapper = new QueryWrapper<>();

        if (StringUtils.hasText(keyword)) {
            queryWrapper.like("name", keyword)
                    .or()
                    .like("archive_number", keyword)
                    .or()
                    .like("description", keyword);
        }

        if (StringUtils.hasText(category)) {
            queryWrapper.eq("category", category);
        }

        if (StringUtils.hasText(securityLevel)) {
            queryWrapper.eq("security_level", securityLevel);
        }

        queryWrapper.orderByDesc("create_time");

        if (!isAdmin) {
            queryWrapper.eq("security_level", "公开");
        }
        return page(new Page<>(page, size), queryWrapper);
    }

    @Override
    @Transactional
    public void deleteArchive(Long id) {
        Archive archive = getById(id);
        if (archive != null) {
            try {
                Files.deleteIfExists(Paths.get(archive.getFilePath()));
            } catch (IOException e) {
                throw new RuntimeException("Failed to delete file", e);
            }
            removeById(id);
        }
    }

    @Override
    @Transactional
    public Archive updateArchive(Archive archive) {
        updateById(archive);
        return archive;
    }

    @Override
    public List<Archive> getArchivesByCategory(String category) {
        return list(new QueryWrapper<Archive>().eq("category", category));
    }

    @Override
    public List<Archive> getArchivesBySecurityLevel(String securityLevel) {
        return list(new QueryWrapper<Archive>().eq("security_level", securityLevel));
    }

    @Override
    public Map<String, Long> getArchives() {
        return baseMapper.countByLevel();
    }

    @Override
    public String view(Long id) {
        Archive archive = getById(id);
        String filePath = archive.getFilePath();
        String content = FileUtil.readString(new File(filePath), Charset.defaultCharset());
        return content;
    }

    private String formatFileSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }
} 